//******************************************************************************
//this code is protected by the GNU affero GPLv3
//author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//                        <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include "globals.h"

static s8 set_cursor(struct client *c,s32 pointer_slot,struct msg *m)
{
  s8 r;
  if(m->req_dws<6){
    PERR("client(%d):fatal:pointer::set_cursor missing data\n",c->so);
    r=LWL_ERR;goto exit;
  }

  LOG_WIRE("client(%d):pointer::set_cursor serial=%u surface_id=%u"
                       " hotspot_x=%d hotspot_y=%d\n",c->so,m->req[2],m->req[3],
                                                 (s32)m->req[4],(s32)m->req[5]);

  r=pointer_set_cusor(c,pointer_slot,m->req[2],m->req[3],(s32)m->req[4],
                                                              (  s32)m->req[5]);

exit:
  return r;
}

s8 wl_pointer_req(struct client *c,s32 pointer_slot,struct msg *m)
{
  s8 r;
  switch(m->req_op){
  case WL_POINTER_SET_CURSOR:
    r=set_cursor(c,pointer_slot,m);
    break;
  case WL_POINTER_CLOSE:
    LOG_WIRE("client(%d):pointer::close pointer_id=%u\n",c->so,m->req[0]);
    r=pointer_close(c,pointer_slot);
    break;
  default:
    PERR("client(%d):fatal:pointer unknown opcode %u\n",c->so,m->req_op);
    r=LWL_ERR;
  };
  return r;
}

#define EV_ENTER_DWS 6
s8 wl_pointer_ev_enter(struct client *c,u32 pointer_id,u32 serial,
                                     u32 surface_id,u32 surface_x,u32 surface_y)
{
  u32 ev[EV_ENTER_DWS];

  ev[0]=pointer_id;
  u16 ev_sz=EV_ENTER_DWS*sizeof(u32);
  ev[1]=ev_sz<<16|WL_POINTER_ENTER;
  ev[2]=serial;
  ev[3]=surface_id;
  ev[4]=surface_x;
  ev[5]=surface_y;

  struct io_vec iov;
  iov.base=&ev;
  iov.len=ev_sz;

  struct msg_hdr msg;
  memset(&msg,0,sizeof(msg));
  msg.iov=&iov;
  msg.iov_len=1;

  LOG_WIRE("client(%d):pointer::enter pointer_id=%u serial=%u surface_id=%u"
                 " surface_x=0x%08x surface_y=0x%08x\n",c->so,pointer_id,serial,
                                                surface_id,surface_x,surface_y);

  l r;
  while(1){r=sendmsg(c->so,&msg,0); if(r!=-EINTR) break;}

  if(ISERR(r)){
    PERR("client(%d):fatal(%ld):pointer::enter unable to send event\n",c->so,r);
    r=LWL_ERR;goto exit;
  }

  if(r!=ev_sz){
    PERR("client(%d):fatal:pointer::enter only %ld/%ld were sent\n",c->so,r,
                                                                         ev_sz);
    r=LWL_ERR;goto exit;
  }

  r=LWL_OK;

exit:
  return (s8)r;
}

#define EV_LEAVE_DWS 4
s8 wl_pointer_ev_leave(struct client *c,u32 pointer_id,u32 serial,
                                                                 u32 surface_id)
{
  u32 ev[EV_LEAVE_DWS];

  ev[0]=pointer_id;
  u16 ev_sz=EV_LEAVE_DWS*sizeof(u32);
  ev[1]=ev_sz<<16|WL_POINTER_LEAVE;
  ev[2]=serial;
  ev[3]=surface_id;

  struct io_vec iov;
  iov.base=&ev;
  iov.len=ev_sz;

  struct msg_hdr msg;
  memset(&msg,0,sizeof(msg));
  msg.iov=&iov;
  msg.iov_len=1;

  LOG_WIRE("client(%d):pointer::leave pointer_id=%u serial=%u surface_id=%u\n",
                                            c->so,pointer_id,serial,surface_id);

  l r;
  while(1){r=sendmsg(c->so,&msg,0); if(r!=-EINTR) break;}

  if(ISERR(r)){
    PERR("client(%d):fatal(%ld):pointer::leave unable to send event\n",c->so,r);
    r=LWL_ERR;goto exit;
  }

  if(r!=ev_sz){
    PERR("client(%d):fatal:pointer::leave only %ld/%ld were sent\n",c->so,r,
                                                                         ev_sz);
    r=LWL_ERR;goto exit;
  }

  r=LWL_OK;

exit:
  return (s8)r;
}

#define EV_MOTION_DWS 5
s8 wl_pointer_ev_motion(struct client *c,u32 pointer_id,u32 time,u32 surface_x,
                                                                  u32 surface_y)
{
  u32 ev[EV_MOTION_DWS];

  ev[0]=pointer_id;
  u16 ev_sz=EV_MOTION_DWS*sizeof(u32);
  ev[1]=ev_sz<<16|WL_POINTER_MOTION;
  ev[2]=time;
  ev[3]=surface_x;
  ev[4]=surface_y;

  struct io_vec iov;
  iov.base=&ev;
  iov.len=ev_sz;

  struct msg_hdr msg;
  memset(&msg,0,sizeof(msg));
  msg.iov=&iov;
  msg.iov_len=1;

  LOG_WIRE("client(%d):pointer::motion pointer_id=%u time=%u surface_x=0x%08x"
               " surface_y=0x%08x\n",c->so,pointer_id,time,surface_x,surface_y);

  l r;
  while(1){r=sendmsg(c->so,&msg,0); if(r!=-EINTR) break;}

  if(ISERR(r)){
    PERR("client(%d):fatal(%ld):pointer::motion unable to send event\n",c->so,
                                                                             r);
    r=LWL_ERR;goto exit;
  }

  if(r!=ev_sz){
    PERR("client(%d):fatal:pointer::motion only %ld/%ld were sent\n",c->so,r,
                                                                         ev_sz);
    r=LWL_ERR;goto exit;
  }

  r=LWL_OK;

exit:
  return (s8)r;
}

#define EV_BUTTON_DWS 6
s8 wl_pointer_ev_button(struct client *c,u32 pointer_id,u32 serial,u32 time,
                                                           u32 button,u32 state)
{
  u32 ev[EV_BUTTON_DWS];

  ev[0]=pointer_id;
  u16 ev_sz=EV_BUTTON_DWS*sizeof(u32);
  ev[1]=ev_sz<<16|WL_POINTER_BUTTON;
  ev[2]=serial;
  ev[3]=time;
  ev[4]=button;
  ev[5]=state;

  struct io_vec iov;
  iov.base=&ev;
  iov.len=ev_sz;

  struct msg_hdr msg;
  memset(&msg,0,sizeof(msg));
  msg.iov=&iov;
  msg.iov_len=1;

  LOG_WIRE("client(%d):pointer::button pointer_id=%u serial=%u time=%u"
             " button=%u state=%u\n",c->so,pointer_id,serial,time,button,state);

  l r;
  while(1){r=sendmsg(c->so,&msg,0); if(r!=-EINTR) break;}

  if(ISERR(r)){
    PERR("client(%d):fatal(%ld):pointer::button unable to send event\n",c->so,
                                                                             r);
    r=LWL_ERR;goto exit;
  }

  if(r!=ev_sz){
    PERR("client(%d):fatal:pointer::button only %ld/%ld were sent\n",c->so,r,
                                                                         ev_sz);
    r=LWL_ERR;goto exit;
  }

  r=LWL_OK;

exit:
  return (s8)r;
}

#define EV_AXIS_DWS 5
s8 wl_pointer_ev_axis(struct client *c,u32 pointer_id,u32 time,u32 axis,
                                                                      u32 value)
{
  u32 ev[EV_AXIS_DWS];

  ev[0]=pointer_id;
  u16 ev_sz=EV_AXIS_DWS*sizeof(u32);
  ev[1]=ev_sz<<16|WL_POINTER_AXIS;
  ev[2]=time;
  ev[3]=axis;
  ev[4]=value;

  struct io_vec iov;
  iov.base=&ev;
  iov.len=ev_sz;

  struct msg_hdr msg;
  memset(&msg,0,sizeof(msg));
  msg.iov=&iov;
  msg.iov_len=1;

  LOG_WIRE("client(%d):pointer::axis pointer_id=%u time=%u axis=%u"
                            " value=0x%08x\n",c->so,pointer_id,time,axis,value);

  l r;
  while(1){r=sendmsg(c->so,&msg,0); if(r!=-EINTR) break;}

  if(ISERR(r)){
    PERR("client(%d):fatal(%ld):pointer::axis unable to send event\n",c->so,r);
    r=LWL_ERR;goto exit;
  }

  if(r!=ev_sz){
    PERR("client(%d):fatal:pointer::axis only %ld/%ld were sent\n",c->so,r,
                                                                         ev_sz);
    r=LWL_ERR;goto exit;
  }

  r=LWL_OK;

exit:
  return (s8)r;
}
